﻿using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using System.Threading;

namespace WPFMetronom
{
	public partial class MainWindow : Window
	{
		#region Declarations

		private bool mbPlaying = false;
		private bool mbPlayButtonActive = false;
		private bool mbFormLoad = false;
		private bool mbOneThread = true;
		private string msFileNameToSavePreset = "preset.prob";
		private int miCurrentSpeed = 0;

		private MySoundPlayer moSoundPlayer;
		private Thread mtThreadPlayer;
		private BackgroundWorker moWorker;
		private Slider moCurrentSlider;
		private PresetObj moPresetObj;

		//при нажатии кнпоки меняется её смысл: true - первое слово
		private bool mbSimpleOrExtend = false;
		public bool SimpleOrExtend
		{
			get { return mbSimpleOrExtend; }
			set { mbSimpleOrExtend = value; }
		}

		private bool mbStepOrPart = true;
		public bool StepOrPart
		{
			get { return mbStepOrPart; }
			set { mbStepOrPart = value; }
		}

		private bool mbTimeOrHit = true;
		public bool TimeOrHit
		{
			get { return mbTimeOrHit; }
			set { mbTimeOrHit = value; }
		}

		private bool mbRepeatOrLoop = true;
		public bool RepeatOrLoop
		{
			get { return mbRepeatOrLoop; }
			set { mbRepeatOrLoop = value; }
		}

		public string Language = "Rus";

		#endregion

		#region Constructors

		public MainWindow ( )
		{
			try
			{
				InitializeComponent ( );
				mbFormLoad = true;
				WorkerInit ( );
				moPresetObj = new PresetObj ( this );

				moSoundPlayer = new MySoundPlayer ( );

				//чтобы отобразился кружочек
				ReverseRadioButton ( );
			}
			catch ( Exception ex )
			{
				Logger.Log ( ex );
			}
		}

		#endregion

		#region Private Methods

		#region background-worker

		private void WorkerInit ( )
		{
			moWorker = new BackgroundWorker ( );
			moWorker.WorkerSupportsCancellation = true;
			moWorker.DoWork += worker_DoWork;
			moWorker.RunWorkerCompleted += worker_RunWorkerCompleted;
			moWorker.WorkerReportsProgress = true;
			moWorker.ProgressChanged += worker_Changed;
		}

		private void worker_DoWork ( object sender, DoWorkEventArgs e )
		{
			if ( !moWorker.CancellationPending )
			{
				try
				{
					Slider oSlider = (Slider) e.Argument;
					moCurrentSlider = oSlider;
					int iSliderValue = 0;
					oSlider.Dispatcher.Invoke (
						DispatcherPriority.Normal, new Action ( ( ) => { iSliderValue = (int) oSlider.Value; } ) );
					while ( iSliderValue > 0 && mbPlaying )
					{
						if ( moWorker.CancellationPending )
						{
							break;
						}

						iSliderValue--;
						moWorker.ReportProgress ( iSliderValue );
						Thread.Sleep ( 1000 );
					}
				}
				catch ( Exception ex )
				{
					Logger.Log ( ex );
				}
				finally
				{
					mbPlaying = false;
				}
			}
			else
			{
				mbPlaying = false;
			}
		}

		private void worker_Changed ( object sender, ProgressChangedEventArgs e )
		{
			if ( mbPlaying )
			{
				moCurrentSlider.Dispatcher.Invoke (
					new Action ( ( ) => { moCurrentSlider.Value--; } ), DispatcherPriority.Normal );
			}
			else
			{
				moWorker.CancelAsync ( );
			}
		}

		private void worker_RunWorkerCompleted ( object sender, RunWorkerCompletedEventArgs e )
		{
			buttonStart.Dispatcher.Invoke (
				new Action ( ( ) => { buttonStart.Content = "Старт"; } ), DispatcherPriority.Normal );
			mbPlaying = false;
			EndGame ( );
		}

		#endregion

		private void DescretePlay ( )
		{
			mbPlaying = true;
			buttonStart.Dispatcher.Invoke (
				new Action ( ( ) => { buttonStart.Content = "Стоп"; } ), DispatcherPriority.Normal );
			try
			{
				bool bIsSimpleCheck = false;
				radioButtonSimple.Dispatcher.Invoke (
					new Action ( ( ) => { bIsSimpleCheck = (bool) radioButtonSimple.IsChecked; } ), DispatcherPriority.Normal );
				if ( bIsSimpleCheck )
				{
					PlayABlock ( );
				}
				else
				{
					int iSpeedStart = ReturnSliderValue ( sliderSpeedExtendStart );
					int iSpeedFinal = ReturnSliderValue ( sliderSpeedExtendFinish );
					int iRepeats = ReturnSliderValue ( sliderRepeatLoop );
					int iStepPartParameter = ReturnSliderValue ( sliderStepPart );
					int iTimerHitParameter = ReturnSliderValue ( sliderTimeHit );

					int r = iRepeats;
					bool bBoxRepeatLoop = false;
					checkBoxRepeatLoop.Dispatcher.Invoke (
						new Action ( ( ) => { bBoxRepeatLoop = (bool) checkBoxRepeatLoop.IsChecked; } ), DispatcherPriority.Normal );

					mbOneThread = true;
					do
					{
						sliderRepeatLoop.Dispatcher.Invoke (
							new Action ( ( ) => { sliderRepeatLoop.Value = r; } ), DispatcherPriority.Normal );

						if ( mbStepOrPart )
						{
							if ( mbTimeOrHit )
							{
								PlayB0Block ( iSpeedStart, iSpeedFinal, iStepPartParameter, iTimerHitParameter );
							}
							else
							{
								PlayB1Block ( iSpeedStart, iSpeedFinal, iStepPartParameter, iTimerHitParameter );
							}
						}
						else
						{
							int iPart = Math.Abs ( iSpeedFinal - iSpeedStart ) / iStepPartParameter;
							if ( mbTimeOrHit )
							{
								PlayB2Block ( iSpeedStart, iSpeedFinal, iPart, iTimerHitParameter );
							}
							else
							{
								PlayB3Block ( iSpeedStart, iSpeedFinal, iPart, iTimerHitParameter );
							}
						}

						if ( bBoxRepeatLoop )
						{
							r--;
							if ( mbRepeatOrLoop )
							{
								mbPlaying = true;
								if ( r == -1 )
								{
									break;
								}
							}
							else
							{
								mbPlaying = true;
								r = iRepeats;
							}
						}
						else
						{
							r = iRepeats;
						}
					} while ( r != -1 && mbPlayButtonActive && mbPlaying );

					EndGame ( );
				}
			}
			catch ( Exception ex )
			{
				EndGame ( );
				Logger.Log ( ex );
			}
		}

		private void EndGame ( )
		{
			mbPlayButtonActive = mbPlaying = false;
			buttonStart.Dispatcher.Invoke (
				new Action ( ( ) => { buttonStart.Content = "Старт"; } ), DispatcherPriority.Normal );

			this.Dispatcher.Invoke ( new Action ( ( ) =>
			{
				moPresetObj.LoadPreset ( );
				SetCountDownActivated ( );
				radioButtonExtended.IsEnabled = true;
				radioButtonSimple.IsEnabled = true;

				if ( mbSimpleOrExtend )
				{
					ShowSimple ( );
				}
				else
				{
					ShowExtend ( );
				}

			} ), DispatcherPriority.Normal );
		}

		private int ReturnSliderValue ( Slider oSlider )
		{
			int iReturn = 0;
			oSlider.Dispatcher.Invoke ( new Action ( ( ) => { iReturn = (int) oSlider.Value; } ), DispatcherPriority.Normal );
			return iReturn;
		}

		private void CountdownPrePlay ( )
		{
			int iSliderValue = ReturnSliderValue ( sliderCountdown );
			while ( iSliderValue > 0 )
			{
				if ( !mbPlaying )
				{
					EndGame ( );
					return;
				}
				sliderCountdown.Dispatcher.Invoke (
					new Action ( ( ) => { iSliderValue = (int) --sliderCountdown.Value; } ), DispatcherPriority.Normal );
				moSoundPlayer.PlayOnce ( );
				Thread.Sleep ( 1000 );
			}
			DescretePlay ( );
		}

		#endregion

		#region Готовые Play

		private void PlayABlock ( )
		{
			//A-блок
			bool bIsSimpleTime = false;
			checkBoxSimpleTime.Dispatcher.Invoke (
				new Action ( ( ) => { bIsSimpleTime = (bool) checkBoxSimpleTime.IsChecked; } ), DispatcherPriority.Normal );

			sliderSpeedSimple.Dispatcher.Invoke (
					new Action ( ( ) => { miCurrentSpeed = (int) sliderSpeedSimple.Value; } ), DispatcherPriority.Normal );
			mtThreadPlayer = new Thread ( new ThreadStart ( Play ) );
			mtThreadPlayer.IsBackground = true;
			mtThreadPlayer.Start ( );

			if ( bIsSimpleTime )
			{
				//A.0: speed simple + simple timerOn
				moWorker.RunWorkerAsync ( sliderSimpleTimer );
			}
			// else A.1: speed simple + simple timerOff
		}

		private void PlayB0Block ( int iSpeedStart, int iSpeedFinal, int iStep, int iTime )
		{
			sliderTimeHit.Dispatcher.Invoke (
				new Action ( ( ) => { sliderTimeHit.Value = iTime; } ), DispatcherPriority.Normal );

			Thread oThread = null;
			if ( mbOneThread )
			{
				oThread = new Thread ( Play );
				oThread.IsBackground = true;
			}

			for ( int iSpeed = iSpeedStart; ( iSpeed <= iSpeedFinal && iSpeed >= iSpeedStart ) && mbPlayButtonActive; iSpeed += iStep )
			{
				miCurrentSpeed = iSpeed;
				mbPlaying = true;

				if ( mbOneThread && oThread != null )
				{
					oThread.Start ( );
					mbOneThread = false;
				}

				sliderSpeedExtendStart.Dispatcher.Invoke (
					new Action ( ( ) => { sliderSpeedExtendStart.Value = iSpeed; } ), DispatcherPriority.Normal );
				sliderTimeHit.Dispatcher.Invoke (
					new Action ( ( ) => { sliderTimeHit.Value = iTime; } ), DispatcherPriority.Normal );

				for ( int t = iTime; t >= 0 && mbPlaying; t-- )
				{
					sliderTimeHit.Dispatcher.Invoke (
						new Action ( ( ) => { sliderTimeHit.Value--; } ), DispatcherPriority.Normal );
					Thread.Sleep ( 1000 );
				}
				mbPlaying = false;
			}
		}

		private void PlayB1Block ( int iSpeedStart, int iSpeedFinal, int iStep, int iHit )
		{
			sliderTimeHit.Dispatcher.Invoke (
				new Action ( ( ) => { sliderTimeHit.Value = iHit; } ), DispatcherPriority.Normal );

			for ( int iSpeed = iSpeedStart; iSpeed <= iSpeedFinal && mbPlayButtonActive; iSpeed += iStep )
			{
				sliderSpeedExtendStart.Dispatcher.Invoke (
					new Action ( ( ) => { sliderSpeedExtendStart.Value = iSpeed; } ), DispatcherPriority.Normal );
				sliderTimeHit.Dispatcher.Invoke (
					new Action ( ( ) => { sliderTimeHit.Value = iHit; } ), DispatcherPriority.Normal );

				for ( int h = iHit; h > 0 && mbPlayButtonActive; h-- )
				{
					sliderTimeHit.Dispatcher.Invoke (
						new Action ( ( ) => { sliderTimeHit.Value--; } ), DispatcherPriority.Normal );
					moSoundPlayer.PlayOnce ( );
					Thread.Sleep ( (int) ( 60000 / iSpeed ) );
				}
				mbPlaying = false;
			}
		}

		private void PlayB2Block ( int iSpeedStart, int iSpeedFinal, int iPart, int iTime )
		{
			sliderTimeHit.Dispatcher.Invoke (
				new Action ( ( ) => { sliderTimeHit.Value = iTime; } ), DispatcherPriority.Normal );

			Thread oThread = null;
			if ( mbOneThread )
			{
				oThread = new Thread ( Play );
				oThread.IsBackground = true;
			}

			for ( int iSpeed = iSpeedStart; iSpeed <= iSpeedFinal && mbPlayButtonActive; iSpeed += iPart )
			{
				miCurrentSpeed = iSpeed;
				mbPlaying = true;

				if ( mbOneThread && oThread != null )
				{
					oThread.Start ( );
					mbOneThread = false;
				}

				sliderSpeedExtendStart.Dispatcher.Invoke (
					new Action ( ( ) => { sliderSpeedExtendStart.Value = iSpeed; } ), DispatcherPriority.Normal );
				sliderTimeHit.Dispatcher.Invoke (
					new Action ( ( ) => { sliderTimeHit.Value = iTime; } ), DispatcherPriority.Normal );

				for ( int t = iTime; t >= 0 && mbPlaying; t-- )
				{
					sliderTimeHit.Dispatcher.Invoke (
						new Action ( ( ) => { sliderTimeHit.Value--; } ), DispatcherPriority.Normal );
					Thread.Sleep ( 1000 );
				}
				mbPlaying = false;
			}
		}

		private void PlayB3Block ( int iSpeedStart, int iSpeedFinal, int iPart, int iHit )
		{
			sliderTimeHit.Dispatcher.Invoke (
				new Action ( ( ) => { sliderTimeHit.Value = iHit; } ), DispatcherPriority.Normal );

			for ( int iSpeed = iSpeedStart; iSpeed <= iSpeedFinal && mbPlayButtonActive; iSpeed += iPart )
			{
				sliderSpeedExtendStart.Dispatcher.Invoke (
					new Action ( ( ) => { sliderSpeedExtendStart.Value = iSpeed; } ), DispatcherPriority.Normal );
				sliderTimeHit.Dispatcher.Invoke (
					new Action ( ( ) => { sliderTimeHit.Value = iHit; } ), DispatcherPriority.Normal );

				for ( int h = iHit; h > 0 && mbPlayButtonActive; h-- )
				{
					sliderTimeHit.Dispatcher.Invoke (
						new Action ( ( ) => { sliderTimeHit.Value--; } ), DispatcherPriority.Normal );
					moSoundPlayer.PlayOnce ( );
					Thread.Sleep ( (int) ( 60000 / iSpeed ) );
				}
				mbPlaying = false;
			}
		}

		private void Play ( )
		{
			try
			{
				while ( mbPlaying && mbPlayButtonActive )
				{
					moSoundPlayer.PlayOnce ( );
					Thread.Sleep ( (int) ( 60000 / miCurrentSpeed ) );
				}
			}
			catch ( Exception ex )
			{
				Logger.Log ( ex );
				EndGame ( );
			}
		}

		#endregion

	}
}
